package com.snowfield.lb47.lbconfig.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.system.service.ISysConfigService;
import com.snowfield.lb47.lbconfig.domain.*;
import com.snowfield.lb47.lbconfig.mapper.*;
import com.snowfield.lb47.lbconfig.service.IFrontProxyService;
import com.snowfield.lb47.lbconfig.velocityService.HAVelocityService;
import com.snowfield.lb47.lbconfig.velocityService.KAVelocityService;
import com.snowfield.lb47.utils.FrontProxyCache;
import com.snowfield.lbcommon.config.SnowFieldConfig;
import com.snowfield.lbcommon.domain.Cluster;
import com.snowfield.lbcommon.service.IClusterService;
import com.snowfield.lbcommon.utils.CommandUtils;
import com.snowfield.lbcommon.utils.HttpsUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.hc.client5.http.HttpRoute;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.routing.HttpRoutePlanner;
import org.apache.hc.core5.http.ClassicHttpRequest;
import org.apache.hc.core5.http.HttpEntity;
import org.apache.hc.core5.http.HttpException;
import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.http.io.support.ClassicRequestBuilder;
import org.apache.hc.core5.http.protocol.HttpContext;
import org.apache.hc.core5.util.Timeout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.net.URI;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * 前端代理Service业务层处理
 *
 * @author snowfield
 * @date 2024-04-01
 */
@Service
public class FrontProxyServiceImpl implements IFrontProxyService {
    private static final Logger LOGGER = LoggerFactory.getLogger(FrontProxyServiceImpl.class);

    @Autowired
    private FrontProxyMapper frontProxyMapper;
    @Autowired
    private FrontProxyServerMapper frontProxyServerMapper;
    @Autowired
    private FrontProxyAclMapper frontProxyAclMapper;
    @Autowired
    private FrontProxyHeaderMapper frontProxyHeaderMapper;
    @Autowired
    private FrontProxyCrtMapper frontProxyCrtMapper;
    @Autowired
    private BackserverCrtMapper backserverCrtMapper;
    @Autowired
    private HttpCheckParamMapper httpCheckParamMapper;

    @Autowired
    private HAVelocityService haVelocityService;
    @Autowired
    private KAVelocityService kaVelocityService;
    @Autowired
    private IClusterService clusterService;
    @Autowired
    private ISysConfigService sysConfigService;

    /**
     * 1.重新加载前端代理数据到缓存中
     * 2.重新加载前端代理概要信息到缓存中
     * <p>
     * 相当于每次tomcat生新启动后,都重新加载一次数据
     */
    @PostConstruct
    public void initCache() {
        List<FrontProxy> frontProxyList = selectFrontProxyList(new FrontProxy());

        /**
         * 1.重新加载前端代理数据
         */
        FrontProxyCache.clearProxyCache();
        List<FrontProxy> frontProxyList2 = new ArrayList<>();
        for (FrontProxy frontProxy : frontProxyList) {
            frontProxyList2.add(selectFrontProxyById(frontProxy.getId()));
        }
        FrontProxyCache.setProxyCache(frontProxyList2);

        /**
         * 2.重新加载前端代理概要信息
         */
        FrontProxyCache.removeProxySummaryCache();
        Map<String, Map<String, String>> frontProxySummary = new HashMap<>();
        for (FrontProxy frontProxy : frontProxyList) {
            HashMap<String, String> proxyHashMap = new HashMap<>();
            proxyHashMap.put("proxyName", frontProxy.getProxyName());
            proxyHashMap.put("bindIp", frontProxy.getBindIp());
            proxyHashMap.put("bindPort", String.valueOf(frontProxy.getBindPort()));
            proxyHashMap.put("status", frontProxy.getStatus());

            frontProxySummary.put(String.valueOf(frontProxy.getId()), proxyHashMap);
        }

        FrontProxyCache.setProxySummaryCache(frontProxySummary);
    }

    /**
     * 查询前端代理
     *
     * @param id 前端代理主键
     * @return 前端代理
     */
    @Override
    public FrontProxy selectFrontProxyById(Long id) {
        FrontProxy frontProxy = frontProxyMapper.selectFrontProxyById(id);

        //查询服务器数据
        FrontProxyServer queryServerForm = new FrontProxyServer();
        queryServerForm.setProxyId(id);
        List<FrontProxyServer> frontProxyServerList = frontProxyServerMapper.selectFrontProxyServerList(queryServerForm);
        frontProxy.setFrontProxyServerList(frontProxyServerList);

        //查询ACL数据
        FrontProxyAcl queryAclForm = new FrontProxyAcl();
        queryAclForm.setProxyId(id);
        List<FrontProxyAcl> frontProxyAclList = frontProxyAclMapper.selectFrontProxyAclList(queryAclForm);
        frontProxy.setFrontProxyAclList(frontProxyAclList);

        //查询Header数据
        FrontProxyHeader queryHeaderForm = new FrontProxyHeader();
        queryHeaderForm.setProxyId(id);
        List<FrontProxyHeader> frontProxyHeaderList = frontProxyHeaderMapper.selectFrontProxyHeaderList(queryHeaderForm);
        frontProxy.setFrontProxyHeaderList(frontProxyHeaderList);


        /**
         * 生成页面使用的balanceArgsDisplay对象，
         * balanceArgs为String对象，不能在页面直接使用，转化为Map对象
         */
        String balanceArgs = frontProxy.getBalanceArgs();
        if (StringUtils.isEmpty(balanceArgs)) {
            frontProxy.setBalanceArgsDisplay(new HashMap<>());
        } else {
            JSONObject jsonObject = JSONObject.parseObject(balanceArgs);
            HashMap<String, Object> balanceArgsDisplay = new HashMap<>();

            balanceArgsDisplay.put("uriParamType", jsonObject.getString("uriParamType"));
            balanceArgsDisplay.put("uriLen", jsonObject.getIntValue("uriLen", 127));
            balanceArgsDisplay.put("uriDepth", jsonObject.getIntValue("uriDepth", 7));
            balanceArgsDisplay.put("urlParam", jsonObject.getString("urlParam"));
            balanceArgsDisplay.put("hdrName", jsonObject.getString("hdrName"));

            frontProxy.setBalanceArgsDisplay(balanceArgsDisplay);
        }

        /**
         * 生成页面使用的cookieConfigDisplay对象，
         * cookieConfig为String对象，不能在页面直接使用，转化为Map对象
         */
        if (frontProxy.getCookie().equals("1")) {
//        {"cookieName":"server","nocache":"1","httponly":"0","secure":"0"}
            String cookieConfig = frontProxy.getCookieConfig();
            if (StringUtils.isEmpty(cookieConfig)) {
                frontProxy.setCookieConfigDisplay(new HashMap<>());
            } else {
                JSONObject jsonObject = JSONObject.parseObject(cookieConfig);
                HashMap<String, Object> cookieConfigDisplay = new HashMap<>();
                cookieConfigDisplay.put("cookieName", jsonObject.getString("cookieName"));
                cookieConfigDisplay.put("nocache", jsonObject.getString("nocache"));
                cookieConfigDisplay.put("httponly", jsonObject.getString("httponly"));
                cookieConfigDisplay.put("secure", jsonObject.getString("secure"));
                cookieConfigDisplay.put("maxidle", jsonObject.getIntValue("maxidle", 30));
                cookieConfigDisplay.put("maxlife", jsonObject.getIntValue("maxlife", 30));

                frontProxy.setCookieConfigDisplay(cookieConfigDisplay);
            }
        } else {
            frontProxy.setCookieConfigDisplay(new HashMap<>());
        }

        return frontProxy;
    }

    /**
     * 查询前端代理列表
     *
     * @param frontProxy 前端代理
     * @return 前端代理
     */
    @Override
    public List<FrontProxy> selectFrontProxyList(FrontProxy frontProxy) {
        return frontProxyMapper.selectFrontProxyList(frontProxy);
    }

    /**
     * 新增前端代理
     *
     * @param frontProxy 前端代理
     * @return 结果
     */
    @Override
    @Transactional
    public int insertFrontProxy(FrontProxy frontProxy) {
        //如果SSL卸载是关闭状态时，设置代理证书为空
        String offLoading = frontProxy.getSslOffloading();
        if (StringUtils.isEmpty(offLoading) || offLoading.equals("0")) {
            frontProxy.setProxyCrtId(null);
        }
        if (!"httpservice".equals(frontProxy.getHealthCheck())){
            frontProxy.setCheckParamId(0L);
        }
        String httpauth = frontProxy.getHttpauth();
        if (StringUtils.isEmpty(httpauth) || httpauth.equals("0")) {
            frontProxy.setHttpauthPath("/");
            frontProxy.setHttpauthUsername("");
            frontProxy.setHttpauthPasswd("");
        }

        if ("black".equals(frontProxy.getBlackwhiteType())){
            frontProxy.setWhiteListId(0L);
        } else if ("white".equals(frontProxy.getBlackwhiteType())){
            frontProxy.setBlackListId(0L);
        } else {
            frontProxy.setWhiteListId(0L);
            frontProxy.setBlackListId(0L);
        }

        frontProxy.setCreateTime(DateUtils.getNowDate());
        //1.新增前端代理
        Integer affectRows = frontProxyMapper.insertFrontProxy(frontProxy);
        List<FrontProxyServer> frontProxyServerList = frontProxy.getFrontProxyServerList();
        List<FrontProxyAcl> frontProxyAclList = frontProxy.getFrontProxyAclList();
        List<FrontProxyHeader> frontProxyHeaderList = frontProxy.getFrontProxyHeaderList();
        //2.如果新增前端代理成功，同步更新前端代理服务器
        if (affectRows > 0) {
            //2.1新增端代理服务器数据
            for (FrontProxyServer proxyServer : frontProxyServerList) {
                proxyServer.setProxyId(frontProxy.getId());
                frontProxyServerMapper.insertFrontProxyServer(proxyServer);
            }
            //2.2新增ACL数据
            for (FrontProxyAcl proxyAcl : frontProxyAclList) {
                proxyAcl.setProxyId(frontProxy.getId());
                frontProxyAclMapper.insertFrontProxyAcl(proxyAcl);
            }
            //2.3新增Hader数据
            for (FrontProxyHeader proxyHader : frontProxyHeaderList) {
                proxyHader.setProxyId(frontProxy.getId());
                frontProxyHeaderMapper.insertFrontProxyHeader(proxyHader);
            }

            //2.4更新前端代理缓存数据
            FrontProxyCache.setProxyCache(String.valueOf(frontProxy.getId()), frontProxy);
            FrontProxyCache.removeProxySummaryCache();
        }
        return affectRows;
    }

    /**
     * 修改前端代理
     *
     * @param frontProxy 前端代理
     * @return 结果
     */
    @Override
    @Transactional
    public int updateFrontProxy(FrontProxy frontProxy) {
        //如果SSL卸载是关闭状态时，设置代理证书为空
        String offLoading = frontProxy.getSslOffloading();
        if (StringUtils.isEmpty(offLoading) || offLoading.equals("0")) {
            frontProxy.setProxyCrtId(null);
        }
        if (!"httpservice".equals(frontProxy.getHealthCheck())){
            frontProxy.setCheckParamId(0L);
        }
        String httpauth = frontProxy.getHttpauth();
        if (StringUtils.isEmpty(httpauth) || httpauth.equals("0")) {
            frontProxy.setHttpauthPath("/");
            frontProxy.setHttpauthUsername("");
            frontProxy.setHttpauthPasswd("");
        }

        if ("black".equals(frontProxy.getBlackwhiteType())){
            frontProxy.setWhiteListId(0L);
        } else if ("white".equals(frontProxy.getBlackwhiteType())){
            frontProxy.setBlackListId(0L);
        } else {
            frontProxy.setWhiteListId(0L);
            frontProxy.setBlackListId(0L);
        }

        frontProxy.setUpdateTime(DateUtils.getNowDate());
        //1.修改前端代理
        LOGGER.info(String.valueOf(frontProxy.getCheckParamId()));
        Integer affectRows = frontProxyMapper.updateFrontProxy(frontProxy);
        List<FrontProxyServer> frontProxyServerList = frontProxy.getFrontProxyServerList();
        List<FrontProxyAcl> frontProxyAclList = frontProxy.getFrontProxyAclList();
        List<FrontProxyHeader> frontProxyHeaderList = frontProxy.getFrontProxyHeaderList();
        //2.如果修改前端代理成功，同步更新前端代理服务器
        if (affectRows > 0) {
            //2.1清空原前端代理服务器数据,acl数据
            frontProxyServerMapper.deleteFrontProxyServerByProxyIds(new Long[]{frontProxy.getId()});
            frontProxyAclMapper.deleteFrontProxyAclByProxyIds(new Long[]{frontProxy.getId()});
            frontProxyHeaderMapper.deleteFrontProxyHeaderByProxyIds(new Long[]{frontProxy.getId()});
            //2.2插入新前端代理服务器数据
            for (FrontProxyServer proxyServer : frontProxyServerList) {
                proxyServer.setProxyId(frontProxy.getId());
                frontProxyServerMapper.insertFrontProxyServer(proxyServer);
            }
            //2.3插入新前端代理ACL数据
            for (FrontProxyAcl proxyAcl : frontProxyAclList) {
                proxyAcl.setProxyId(frontProxy.getId());
                frontProxyAclMapper.insertFrontProxyAcl(proxyAcl);
            }
            //2.4插入新前端代理Hader数据
            for (FrontProxyHeader proxyHader : frontProxyHeaderList) {
                proxyHader.setProxyId(frontProxy.getId());
                frontProxyHeaderMapper.insertFrontProxyHeader(proxyHader);
            }

            //2.5更新前端代理缓存数据
            FrontProxyCache.setProxyCache(String.valueOf(frontProxy.getId()), frontProxy);
            FrontProxyCache.removeProxySummaryCache();
        }
        return affectRows;
    }

    /**
     * 批量删除前端代理
     *
     * @param ids 需要删除的前端代理主键
     * @return 结果
     */
    @Override
    @Transactional
    public int deleteFrontProxyByIds(Long[] ids) {
        Integer affectRows = frontProxyMapper.deleteFrontProxyByIds(ids);

        if (affectRows > 0) {
            //删除代理服务器关系
            frontProxyServerMapper.deleteFrontProxyServerByProxyIds(ids);
            //删除代理ACL
            frontProxyAclMapper.deleteFrontProxyAclByProxyIds(ids);
            //删除代理Header
            frontProxyHeaderMapper.deleteFrontProxyHeaderByProxyIds(ids);

            //更新前端代理缓存数据
            for (Long id : ids) {
                FrontProxyCache.removeProxyCache(String.valueOf(id));
            }
            FrontProxyCache.removeProxySummaryCache();
        }
        return affectRows;
    }

    /**
     * 删除前端代理信息
     *
     * @param id 前端代理主键
     * @return 结果
     */
    @Override
    public int deleteFrontProxyById(Long id) {
        Integer affectRows = frontProxyMapper.deleteFrontProxyById(id);
        if (affectRows > 0) {
            //删除代理服务器关系
            frontProxyServerMapper.deleteFrontProxyServerByProxyIds(new Long[]{id});
            //删除代理ACL
            frontProxyAclMapper.deleteFrontProxyAclByProxyIds(new Long[]{id});
            //删除代理Header
            frontProxyHeaderMapper.deleteFrontProxyHeaderByProxyIds(new Long[]{id});

            //更新前端代理缓存数据
            FrontProxyCache.removeProxyCache(String.valueOf(id));
            FrontProxyCache.removeProxySummaryCache();
        }
        return affectRows;
    }

    /**
     * 修改前端代理状态
     *
     * @param id     前端代理主键
     * @param status 前端代理状态
     * @return 结果 0:失败，1：成功
     */
    public int changeProxyStatus(Long id, String status) {
        //1.更新代理状态
        Integer affectRows = frontProxyMapper.changeProxyStatus(id, status);
        if (affectRows > 0) {
            //重载策略
            Boolean reloadResult = reloadProxy();

            if (reloadResult) {
                //成功
                return 1;
            } else {
                //失败
                status = "1".equals(status) ? "0" : "1";
                //4.1还原前端代理状态
                frontProxyMapper.changeProxyStatus(id, status);

                return 0;
            }
        }

        return 0;
    }

    /**
     * 重新加载策略
     *
     * @return
     */
    public Boolean reloadProxy() {
        //1.生成新的haproxy配置文件，keepalived配置文件;之前先备份原来的配置文件
        //1.1备份配置文件
        HAVelocityService.backupHAConfigFile();
        KAVelocityService.backupKAConfigFile();
        //1.2生成新的配置文件
        createLBConfigFile();

        //如果生成配置文件成功了
        try {
            File srcFile = new File(SnowFieldConfig.getHaConfigPath() + "/haproxy-velocity.cfg");
            File dstFile = new File("/etc/haproxy/haproxy.cfg");
            File bakFile = new File("/etc/haproxy/haproxy.backup.cfg");
            FileUtils.copyFile(dstFile, bakFile);
            FileUtils.copyFile(srcFile, dstFile);
            File src2File = new File(SnowFieldConfig.getKaConfigPath() + "/keepalived-velocity.conf");
            File dst2File = new File("/etc/keepalived/keepalived.conf");
            File bak2File = new File("/etc/keepalived/keepalived.backup.cfg");
            FileUtils.copyFile(dst2File, bak2File);
            FileUtils.copyFile(src2File, dst2File);
        } catch (IOException e) {
            e.printStackTrace();
        }

        //2.重启keepalived,haproxy
        Integer lbRestartResult = CommandUtils.lbRestart();
        LOGGER.info("lbRestartResult : {}", lbRestartResult);

        //3.如果未启动成功，需要还原前端代理状态及keepalived,haproxy的配置文件并重启
        if (!lbRestartResult.equals(0)) {
            //3.1还原配置文件
            //还原
            try {
                File dstFile = new File("/etc/haproxy/haproxy.cfg");
                File bakFile = new File("/etc/haproxy/haproxy.backup.cfg");
                FileUtils.copyFile(bakFile, dstFile);
                File dst2File = new File("/etc/keepalived/keepalived.conf");
                File bak2File = new File("/etc/keepalived/keepalived.backup.cfg");
                FileUtils.copyFile(bak2File, dst2File);
            } catch (IOException e) {
                e.printStackTrace();
            }

            //3.2重启keepalived,haproxy
            CommandUtils.lbRestart();

            return Boolean.FALSE;
        }
        return Boolean.TRUE;
    }

    /**
     * 校验前端代理名称是否唯一
     *
     * @param frontProxy 前端代理
     * @return 结果
     */
    public Boolean checkNameUnique(FrontProxy frontProxy) {
        Long proxyId = frontProxy.getId();
        FrontProxy proxy = frontProxyMapper.selectFrontProxyByName(frontProxy.getProxyName());
        if (proxy != null && !proxy.getId().equals(proxyId)) {
            return Boolean.FALSE;
        }
        return Boolean.TRUE;
    }

    /**
     * 校验前端代理绑定地址和端口是否唯一
     *
     * @param frontProxy 前端代理
     * @return 结果
     */
    public Boolean checkBindIpPortUnique(FrontProxy frontProxy) {
        Long proxyId = frontProxy.getId();
        FrontProxy proxy = frontProxyMapper.selectFrontProxyByBindIpPort(frontProxy.getBindIp(), frontProxy.getBindPort());
        if (proxy != null && !proxy.getId().equals(proxyId)) {
            return Boolean.FALSE;
        }
        return Boolean.TRUE;
    }

    /**
     * 查询所有的前端代理配置，以生成keepalived及haproxy组件的配置文件
     *
     * @return 结果
     */
    public int createLBConfigFile() {
        //集群配置信息
        Long clusterId = 1L;
        Cluster cluster = clusterService.selectClusterById(clusterId);

        //1.查询前端代理详细信息，并生成haproxy组件的配置文件
        FrontProxy queryForm = new FrontProxy();
        queryForm.setStatus("1");
        //1.1前端代理基本信息集合
        List<FrontProxy> frontProxyList = frontProxyMapper.selectFrontProxyList(queryForm);
        //1.2前端代理详细信息集合
        List<FrontProxy> frontProxyDetailList = new ArrayList<>();
        for (FrontProxy frontProxy : frontProxyList) {
            frontProxyDetailList.add(selectFrontProxyById(frontProxy.getId()));
        }
        //1.3查询所有的前端代理证书信息，在设置SSL卸载时使用证书路径
        HashMap<Long, String> proxyCrtMap = new HashMap<>();
        List<FrontProxyCrt> frontProxyCrtList = frontProxyCrtMapper.selectFrontProxyCrtList(new FrontProxyCrt());
        for (FrontProxyCrt frontProxyCrt : frontProxyCrtList) {
            proxyCrtMap.put(frontProxyCrt.getId(), frontProxyCrt.getCrtPath());
        }
        //1.4查询所有的后端服务器证书信息，在设置服务器时使用证书路径
        HashMap<String, BackserverCrt> backServerCrtMap = new HashMap<>();
        List<BackserverCrt> backserverCrtList = backserverCrtMapper.selectBackserverCrtList(new BackserverCrt());
        for (BackserverCrt backserverCrt : backserverCrtList) {
            backServerCrtMap.put(backserverCrt.getServerId() + ":" + backserverCrt.getCrtPort(), backserverCrt);
        }
        //1.5查的所有的自定义HTTP检测方法信息，在代理配置自定义HTTP检测方法时使用
        HashMap<Long, HttpCheckParam> httpCheckParamMap = new HashMap<>();
        List<HttpCheckParam> httpCheckParamList = httpCheckParamMapper.selectHttpCheckParamList(new HttpCheckParam());
        for (HttpCheckParam checkParam : httpCheckParamList) {
            httpCheckParamMap.put(checkParam.getId(), checkParam);
        }

        haVelocityService.createHaproxyConfigFile(cluster, frontProxyDetailList, proxyCrtMap, backServerCrtMap, httpCheckParamMap);

        //2.查询前端代理基本信息，并生成keepalived组件的配置文件
        List<String> staticIpAddressList = new ArrayList<>();
        //第一个虚拟路由绑定的iP地址
        List<String> virIpAddressListA = new ArrayList<>();
        //第二个虚拟路由绑定的iP地址
        List<String> virIpAddressListB = new ArrayList<>();


        List<String> peerVips = getPeerVips();
        if (peerVips != null) {
            Iterator<FrontProxy> frontProxyIterator = frontProxyList.iterator();
            while (frontProxyIterator.hasNext()) {
                FrontProxy item = frontProxyIterator.next();
                //表示本策略IP不在对端节点策略中，要放到static_address中
                if (!peerVips.contains(item.getBindIp())) {
                    staticIpAddressList.add(item.getBindIp());
                    frontProxyIterator.remove();
                }
            }
        }

        /**
         * 在MM模式下，两类地址分别绑定在不同的vrrp instance中
         * 在MB模式下，两类地址同时绑定在同一个vrrp instance中
         */
        for (FrontProxy frontProxy : frontProxyList) {
            String bindDevice = frontProxy.getBindDevice();
            if (StringUtils.isEmpty(bindDevice) || bindDevice.equals("masterA")) {
                virIpAddressListA.add(frontProxy.getBindIp());
            } else if (bindDevice.equals("masterB")) {
                virIpAddressListB.add(frontProxy.getBindIp());
            }
        }
        kaVelocityService.createKeepalivedConfigFile(cluster, staticIpAddressList, virIpAddressListA, virIpAddressListB);

        return 1;
    }

    /**
     * 查询前端代理概要信息
     * 概要信息主要包括：代理ID、名称、绑定地址、绑定端口、状态
     * 1.如果redis缓存中不存在，从数据库中查询，并添加到缓存中
     * 2.如果redis缓存中存在，直接从缓存中获取
     * 3.每次代理信息有变化，都要更新缓存中的数据
     *
     * @return 前端代理
     */
    @Override
    public Map<String, Map<String, String>> selectFrontProxySummary() {
        Map<String, Map<String, String>> proxySummary = FrontProxyCache.getProxySummaryCache();
        if (proxySummary == null || proxySummary.isEmpty()) {
            //缓存数据不存在，从数据库中获取并加入到缓存
            List<FrontProxy> frontProxyList = frontProxyMapper.selectFrontProxyList(new FrontProxy());
            Map<String, Map<String, String>> frontProxySummary = new HashMap<>();
            for (FrontProxy item : frontProxyList) {
                HashMap<String, String> itemHashMap = new HashMap<>();
                itemHashMap.put("proxyName", item.getProxyName());
                itemHashMap.put("bindIp", item.getBindIp());
                itemHashMap.put("bindPort", String.valueOf(item.getBindPort()));
                itemHashMap.put("status", item.getStatus());

                frontProxySummary.put(String.valueOf(item.getId()), itemHashMap);
            }

            FrontProxyCache.setProxySummaryCache(frontProxySummary);

            return frontProxySummary;
        }
        //缓存中存在
        return proxySummary;
    }

    /**
     * 检测前端代理配置是否正常
     *
     * @param id 前端代理主键
     * @return 结果
     */
    public String checkProxyConfig(Long id) {
        //集群配置信息
        Long clusterId = 1L;
        Cluster cluster = clusterService.selectClusterById(clusterId);

        //1.查询前端代理详细信息，并生成haproxy组件的配置文件
        //1.1前端代理详细信息
        FrontProxy frontProxy = selectFrontProxyById(id);
        //1.2查询所有的前端代理证书信息，在设置SSL卸载时使用证书路径
        HashMap<Long, String> proxyCrtMap = new HashMap<>();
        List<FrontProxyCrt> frontProxyCrtList = frontProxyCrtMapper.selectFrontProxyCrtList(new FrontProxyCrt());
        for (FrontProxyCrt frontProxyCrt : frontProxyCrtList) {
            proxyCrtMap.put(frontProxyCrt.getId(), frontProxyCrt.getCrtPath());
        }
        //1.3查询所有的后端服务器证书信息，在设置服务器时使用证书路径
        HashMap<String, BackserverCrt> backServerCrtMap = new HashMap<>();
        List<BackserverCrt> backserverCrtList = backserverCrtMapper.selectBackserverCrtList(new BackserverCrt());
        for (BackserverCrt backserverCrt : backserverCrtList) {
            backServerCrtMap.put(backserverCrt.getServerId() + ":" + backserverCrt.getCrtPort(), backserverCrt);
        }
        //1.4查的所有的自定义HTTP检测方法信息，在代理配置自定义HTTP检测方法时使用
        HashMap<Long, HttpCheckParam> httpCheckParamMap = new HashMap<>();
        List<HttpCheckParam> httpCheckParamList = httpCheckParamMapper.selectHttpCheckParamList(new HttpCheckParam());
        for (HttpCheckParam checkParam : httpCheckParamList) {
            httpCheckParamMap.put(checkParam.getId(), checkParam);
        }

        haVelocityService.createHaproxyConfigCheckFile(cluster, frontProxy, proxyCrtMap, backServerCrtMap, httpCheckParamMap);
        String configFilePath = SnowFieldConfig.getHaConfigPath() + "/haproxy-velocity-" + frontProxy.getId() + ".cfg";
        File configFile = new File(configFilePath);
        String checkResult = null;
        if (configFile.exists()) {
            String resultFilePath = SnowFieldConfig.getHaConfigPath() + "/haproxy-velocity-" + frontProxy.getId() + ".log";
            Integer commandResult = CommandUtils.checkHaproxyConfigFile(configFilePath, resultFilePath);
            File resultFile = new File(resultFilePath);
            if (resultFile.exists()) {
                try {
                    checkResult = FileUtils.readFileToString(resultFile, StandardCharsets.UTF_8);
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    FileUtils.deleteQuietly(configFile);
                    FileUtils.deleteQuietly(resultFile);
                }
            } else {
                checkResult = "Check configuration file wrong.";
            }
        } else {
            checkResult = "Configuration file is not exist.";
        }

        return checkResult;
    }


    /**
     * 获取其它节点的运行策略VIP地址
     *
     * @return 结果
     */
    public List<String> getPeerVips() {
        //查询集群配置信息
        Cluster cluster = clusterService.selectClusterById(1L);
        //对端设备IP地址
        String peerIp = cluster.getPeerIp();
        //本机设备IPO地址
        String deviceIp = cluster.getDeviceIp();
        if (StringUtils.isEmpty(peerIp) || StringUtils.isEmpty(deviceIp)) {
            LOGGER.error("请正确配置源地址和目标");
            return null;
        }

        try {
            RequestConfig config = RequestConfig.custom().setConnectionRequestTimeout(Timeout.ofSeconds(3L))//设置请求超时时间
                    .setResponseTimeout(Timeout.ofSeconds(3L))//设置响应超时时间
                    .setRedirectsEnabled(true)//默认允许自动重定向
                    .setCircularRedirectsAllowed(false).setMaxRedirects(3).build();
            //创建httproute，可设置本地网络地址，即通过此地址发起访问请求
            HttpRoutePlanner routePlanner = new HttpRoutePlanner() {
                @Override
                public HttpRoute determineRoute(HttpHost httpHost, HttpContext httpContext) throws HttpException {
                    try {
                        InetAddress theAddress = InetAddress.getByName(deviceIp);
                        HttpRoute httpRoute = new HttpRoute(httpHost, theAddress, true);
                        return httpRoute;
                    } catch (UnknownHostException e) {
                        e.printStackTrace();
                        return null;
                    }
                }
            };

            CloseableHttpClient httpClient = HttpsUtils.getHttpClient(config, routePlanner);

//            String requestUrl = "http://" + peerIp + ":8081/lbconfig/frontproxy/getVips"; //本机访问测试
            String requestUrl = "https://" + peerIp + ":443/prod-api/lbconfig/frontproxy/getVips";

            String clusterAccessKey = sysConfigService.selectConfigByKey("cluster.access.key");
            //请求数据
            final ClassicHttpRequest httpGet = ClassicRequestBuilder.get()
                    .setUri(new URI(requestUrl))
                    .addParameter("access_key", clusterAccessKey)
                    .build();

            String resultJson = httpClient.execute(httpGet, aResponse -> {
                HttpEntity httpEntity = aResponse.getEntity();
                String responseString = null;
                if (httpEntity != null) {
                    responseString = EntityUtils.toString(httpEntity, StandardCharsets.UTF_8);
                }
                return responseString;
            });

            JSONObject resultObject = JSON.parseObject(resultJson);
            List<String> vipList = resultObject.getList("data", String.class);
            return vipList;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
